/**
 *  openaltimeter field downloader
 *  by Joe Smallman
 *  4/6/11
 *  
 *  currently uses androidPlot and Amarino APIs
 */

package com.myApps.oaFieldDownloader2;

import java.util.LinkedList;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;
import at.abraxas.amarino.Amarino;
import at.abraxas.amarino.AmarinoIntent;

import com.androidplot.xy.LineAndPointFormatter;
import com.androidplot.xy.LineAndPointRenderer;
import com.androidplot.xy.SimpleXYSeries;
import com.androidplot.xy.XYPlot;

public class oaFieldDownloader extends Activity {

	// change this to your Bluetooth device address 
	private static final String DEVICE_ADDRESS =  "00:06:66:04:D6:DB";

	private static final String DELIMS = "[=]";
	
	private static final long TIMEOUT_INTVL_MILLIS = 10000;	
	private boolean mDataDownloaded;
	
	private TextView mHeightTitle;
	private TextView mValue;
	private XYPlot mAltPlot;
	
	private int mLowestAlt = 0;
	private int mHighestAlt = 0;
	
	private LinkedList<Number> mAltList = new LinkedList<Number>();
	private SimpleXYSeries mAltSeries = new SimpleXYSeries("Altitude");

	private ArduinoReceiver arduinoReceiver = new ArduinoReceiver();
	
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        initialiseUI();
    }
    
    @Override
	public void onConfigurationChanged(Configuration newConfig){
		super.onConfigurationChanged(newConfig);
		
		initialiseUI();
	}
    
    public void initialiseUI()
    {
    	setContentView(R.layout.main);
        
        // get handles to Views defined in our layout file
    	
           mValue = (TextView)findViewById(R.id.maxHeightValue);
           mHeightTitle = (TextView)findViewById(R.id.heightTitle);
           mAltPlot = (XYPlot)findViewById(R.id.altPlot);
           mAltPlot.addSeries(mAltSeries, LineAndPointRenderer.class, new LineAndPointFormatter(Color.BLACK, null, null));
           mAltPlot.setDomainLabel("Samples");
           mAltPlot.getDomainLabelWidget().pack();
           mAltPlot.setRangeLabel("Alt");
           mAltPlot.getRangeLabelWidget().pack();
           mAltPlot.disableAllMarkup();
    }
    
    @Override
	protected void onStart() {
		super.onStart();
		// in order to receive broadcasted intents we need to register our receiver
		registerReceiver(arduinoReceiver, new IntentFilter(AmarinoIntent.ACTION_RECEIVED));
		
		// this is how you tell Amarino to connect to a specific BT device from within your own code
		Amarino.connect(this, DEVICE_ADDRESS);
	}

	@Override
	protected void onStop() {
		super.onStop();
		
		// if you connect in onStart() you must not forget to disconnect when your app is closed
		Amarino.disconnect(this, DEVICE_ADDRESS);
		
		// do never forget to unregister a registered receiver
		unregisterReceiver(arduinoReceiver);
	}
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.menu, menu);
		return true;
	}
	
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
	    switch (item.getItemId()) {
	        case R.id.downloadLastFlight:     
	        	getData();
	            break;
	        case R.id.outputMaxHeight:     
	        	outputMaxHeight();
	            break;
	        case R.id.singFlight:     
	        	singFlight();
	            break;
	        case R.id.fakeAFlightOnArduino:     
	        	arduinoFakeAFlight();
	            break;
	        case R.id.eraseOADataLog:     
	        	eraseArduinoDataLog();
	            break;
	        case R.id.fakeAFlightOnAndroid:
	        	androidFakeAFlightAndPlot();
	        	break;
	    }
	    return true;
	}

    public void resetData(){
    	mLowestAlt = 0;
    	mHighestAlt = 0;
    	mAltList.clear();
    	mDataDownloaded = false;
    }
    
    public void getData(){
    	resetData();
    	Amarino.sendDataToArduino(this, DEVICE_ADDRESS, 'O', ' ');
    	final ProgressDialog dialog = ProgressDialog.show(this, "", "Downloading last flight. Please wait...", true);
    	final Handler handler = new Handler(){
    		public void handleMessage(Message msg) {
    			dialog.dismiss();
    			switch (msg.what){
    				case RESULT_CANCELED:
    					Toast toast = Toast.makeText(getApplicationContext(), "download timed out", Toast.LENGTH_SHORT);
    					toast.show();
    					break;
    				case RESULT_OK:
    					plotFlight();
    					break;
    			}    			
    		}
    	};
    	Thread downloadWait = new Thread() {
    		public void run() {
    			long startTimeMillis = SystemClock.uptimeMillis();
    			// now loop until data is ready or timeout exceeded
    			while (true)
        		{
    				if (mDataDownloaded==true)
        			{
        				handler.sendMessage(handler.obtainMessage(RESULT_OK));
        				break;
        			}
        			//timeout if too long
        			if (SystemClock.uptimeMillis() - startTimeMillis > TIMEOUT_INTVL_MILLIS)
        			{
        				handler.sendMessage(handler.obtainMessage(RESULT_CANCELED));
        				break;
        			}
        			
        		}
    			
    		}
    	};
    	downloadWait.start();
    }
    
    public void eraseArduinoDataLog(){
    	
    	DialogInterface.OnClickListener mDialogClickListener = new DialogInterface.OnClickListener() {
     	   public void onClick(DialogInterface dialog, int which) {
     		   switch (which){
						case DialogInterface.BUTTON_POSITIVE:
							Amarino.sendDataToArduino(getApplicationContext(), DEVICE_ADDRESS, 'e', ' ');
							Toast toast = Toast.makeText(getApplicationContext(), "erasing OA data log", Toast.LENGTH_SHORT);
							toast.show();
							break;
						case DialogInterface.BUTTON_NEGATIVE:
							//do nothing
							break;
     		   }
     	   }
        };
    	
    	AlertDialog.Builder builder = new AlertDialog.Builder(this);
    	builder.setMessage("are you sure?").setPositiveButton("yes", mDialogClickListener).setNegativeButton("no", mDialogClickListener).show();
    }

    public void outputMaxHeight(){
    	resetData();
    	Amarino.sendDataToArduino(this, DEVICE_ADDRESS, 'o', ' ');
    }
    
    public void singFlight(){
    	Amarino.sendDataToArduino(this, DEVICE_ADDRESS, 'l', ' ');
    }
	
    public void arduinoFakeAFlight(){
    	Amarino.sendDataToArduino(this, DEVICE_ADDRESS, 'f', ' ');
    }
    
    public void androidFakeAFlightAndPlot(){
    	resetData();
    	for (int i = 0; i < 10; i++)
    	{
    		mAltList.addLast(10*i);
    	}
    	for (int i = 0; i < 20; i++)
    	{
    		mAltList.addLast(150-2*i);
    	}
    	for (int i = 0; i < 20; i++)
    	{
    		mAltList.addLast(110);
    	}
    	for (int i = 0; i < 50; i++)
    	{
    		mAltList.addLast(110+5*i);
    	}
    	for (int i = 0; i < 36; i++)
    	{
    		mAltList.addLast(360-10*i);
    	}
    	Integer[] tempAltList = new Integer[mAltList.size()];
    	mAltList.toArray(tempAltList);
    	for (int i = 0; i < mAltList.size(); i++)
    	{
    		if (tempAltList[i] < mLowestAlt ) mLowestAlt = tempAltList[i];
    		if (tempAltList[i] > mHighestAlt ) mHighestAlt = tempAltList[i];
    	}
    	
    	plotFlight();
    }
     
	public void plotFlight() {
		mValue.setText(Integer.toString(mHighestAlt-mLowestAlt));
		mAltSeries.setModel(mAltList, SimpleXYSeries.ArrayFormat.Y_VALS_ONLY);
		mAltPlot.redraw();
	}
	
	/**
	 * ArduinoReceiver is responsible for catching broadcasted Amarino
	 * events. 
	 */
	public class ArduinoReceiver extends BroadcastReceiver {

		@Override
		public void onReceive(Context context, Intent intent) {
			String data = null;
			
			// the device address from which the data was sent, we don't need it here but to demonstrate how you retrieve it
			final String address = intent.getStringExtra(AmarinoIntent.EXTRA_DEVICE_ADDRESS);
			
			// the type of data which is added to the intent
			final int dataType = intent.getIntExtra(AmarinoIntent.EXTRA_DATA_TYPE, -1);
			
			// we only expect String data though, but it is better to check if really string was sent
			// later Amarino will support differnt data types, so far data comes always as string and
			// you have to parse the data to the type you have sent from Arduino, like it is shown below
			if (dataType == AmarinoIntent.STRING_EXTRA){
				data = intent.getStringExtra(AmarinoIntent.EXTRA_DATA);				
				if (data != null){
					String[] strBuff = data.split(DELIMS);
					
					if (strBuff.length > 1)
					{
						try {
							// since we know that our string value is an int number we can parse it to an integer
							final int alt = Integer.parseInt(strBuff[1]);
							mAltList.addLast(alt);						
							if (alt < mLowestAlt) mLowestAlt = alt;
							if (alt > mHighestAlt) mHighestAlt = alt;

						} 
						catch (NumberFormatException e) { /* oh data was not an integer */ }
					}
					if(strBuff[0].equals("end")) 
					{
						// raise download complete flag
						mDataDownloaded = true;
					}		
				}
			}
		}
	}
}